#include "game_obj.h"
#include <stdlib.h>
#include <string.h>

// 创建地图
Map Create_Map(uchar w, uchar h)
{
    uchar size_byte = Rounded_up((float)(w * h) / 8);

    Map map;
    map.w = w;
    map.h = h;
    map.size_byte = size_byte;
    map.map = (byte *)malloc(sizeof(byte) * size_byte);

    return map;
}

// 销毁地图
void Destroy_Map(Map map)
{
    free(map.map);
}

// 创建方块集
BlockSet Create_BlockSet(uchar num)
{
    BlockSet blockset;

    blockset.num = num;
    blockset.position = (Vec2 *)malloc(sizeof(Vec2) * num);

    return blockset;
}

// 销毁方块集
void Destroy_BlockSet(BlockSet blockset)
{
    free(blockset.position);
}

// 方块集在水平方向上移动n格
void Move_BlockSet_X(BlockSet blockset, char n)
{
    for (int i = 0; i < blockset.num; i++)
    {
        ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x += n;
    }
}

// 方块集在垂直方向上移动n格
void Move_BlockSet_Y(BlockSet blockset, char n)
{
    for (int i = 0; i < blockset.num; i++)
    {
        ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->y += n;
    }
}

// 方块集在移动[x1,y1]格
void Move_BlockSet(BlockSet blockset, Vec2 n)
{
    for (int i = 0; i < blockset.num; i++)
    {
        ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x += n.x;
        ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->y += n.y;
    }
}

// 获取地图某点的状态
// map: 传入地图
// p: 对应点坐标
// return: 对应坐标点的状态 （TRUE or FALSE)
BOOL Get_Map_Point_Status(Map map, Vec2 p)
{
    uint bit_idx, byte_idx;
    uchar byte = 128; // 0B 1000 0000
    bit_idx = map.w * p.y + p.x;
    byte_idx = bit_idx / 8;
    // bit_idx % 8 = 4;
    // 1011 1010
    // &
    // 0000 1000  // 1000 0000 >> (bit_idx % 8) = 0000 1000
    // ==
    // 0000 1000
    // TRUE
    return *(map.map + byte_idx) & (byte >> (bit_idx % 8)) == byte >> (bit_idx % 8);
}

// TODO 未进行边界判定
// 以物理的方式，向右移动一格
// 即在右边无障碍物的情况下向右移动一格。
void Physics_Move_BlockSet_Right(BlockSet blockset, Map map)
{
    int i;
    uchar vertex_right_X = 0;
    uchar vertex_num = 0;
    uchar *vertex_ringt_Y = (uchar *)malloc(blockset.num);
    BOOL flag = FALSE;

    // 遍历blockset得到X的最大值
    for (i = 0; i < blockset.num; i++)
    {
        if (((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x > vertex_right_X)
        {
            vertex_right_X = ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x;
        }
    }

    // 遍历blockset记录右顶点的Y值
    for (i = 0; i < blockset.num; i++)
    {
        if (((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x == vertex_right_X)
        {
            vertex_ringt_Y[vertex_num] = ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->y;
            vertex_num++;
        }
    }

    // 检测是否即将发送碰撞
    for (i=0;i<blockset.num;i++){
        Vec2 temp;
        temp.x = vertex_right_X+1;
        temp.y = vertex_ringt_Y[i];
        flag = Get_Map_Point_Status(map,temp)==TRUE?TRUE:flag;
    }

    if (!flag){
        Move_BlockSet_X(blockset,1);
    }

    free(vertex_ringt_Y);
}


// TODO 未进行边界判定
// 以物理的方式，向右移动一格
// 即在右边无障碍物的情况下向右移动一格。
void Physics_Move_BlockSet_Left(BlockSet blockset, Map map)
{
    int i;
    uchar vertex_right_X = 0;
    uchar vertex_num = 0;
    uchar *vertex_ringt_Y = (uchar *)malloc(blockset.num);
    BOOL flag = FALSE;

    // 遍历blockset得到X的最大值
    for (i = 0; i < blockset.num; i++)
    {
        if (((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x > vertex_right_X)
        {
            vertex_right_X = ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x;
        }
    }

    // 遍历blockset记录右顶点的Y值
    for (i = 0; i < blockset.num; i++)
    {
        if (((Vec2 *)(blockset.position + sizeof(Vec2) * i))->x == vertex_right_X)
        {
            vertex_ringt_Y[vertex_num] = ((Vec2 *)(blockset.position + sizeof(Vec2) * i))->y;
            vertex_num++;
        }
    }

    // 检测是否即将发送碰撞
    for (i=0;i<blockset.num;i++){
        Vec2 temp;
        temp.x = vertex_right_X-1;
        temp.y = vertex_ringt_Y[i];
        flag = Get_Map_Point_Status(map,temp)==TRUE?TRUE:flag;
    }

    if (!flag){
        Move_BlockSet_X(blockset,-1);
    }

    free(vertex_ringt_Y);
}

// 合并方块集
BlockSet Merge_BlockSet(BlockSet blockset_1, BlockSet blockset_2)
{
    BlockSet result = Create_BlockSet(blockset_1.num + blockset_2.num);
    memmove(result.position, blockset_1.position, sizeof(Vec2) * blockset_1.num);
    memmove(result.position + sizeof(Vec2) * blockset_1.num, blockset_2.position, sizeof(Vec2) * blockset_2.num);
    return result;
}
